# -*- coding: utf-8 -*-
"""
   Copyright (C) 2013 Miguel de Dios

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   higher any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
"""
from Util import *
from Frontend import *

import time
import sys
import os
import threading
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import cgi
import urlparse
import re
import Cookie
import md5
import subprocess, signal

import string

import pprint

class WebAdmin:
	util = None
	thread = None
	stop = False
	server = None
	
	def __init__(self, util_param = None):
		self.util = util_param
	
	class MyHTTPServer(HTTPServer):
		util = None
		exit = False
		
		def __init__(self, *args, **kw):
			HTTPServer.__init__(self, *args, **kw)
	
	class Server(BaseHTTPRequestHandler):
		login = False
		message = ""
		
		def exit_thread(self):
			
			time.sleep(5)
			self.server.socket.close()
			self.server.shutdown()
			
			python = sys.executable
			os.execl(python, python, * sys.argv)
			os._exit(0)
		
		
		def kill_mame(self):
			p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE)
			out, err = p.communicate()
			for line in out.splitlines():
				if self.server.util.options['mame_executable'] in line:
					pid = int(line.split(None, 1)[0])
					os.kill(pid, signal.SIGKILL)
		
		
		def do_GET(self):
			try:
				parsed_path = urlparse.urlparse(self.path)
				
				if "Cookie" in self.headers:
					cookie = Cookie.SimpleCookie(self.headers["Cookie"])
					fake_session = cookie['fake_session'].value
					
					check_fake_session = md5.new()
					check_fake_session.update("salt_pyretro" + self.server.util.options['webadmin_password'])
					check_fake_session = check_fake_session.hexdigest()
					
					if check_fake_session == fake_session:
						self.login = True
					else:
						self.login = False
				
				
				if parsed_path.path in ("/", "/index.htm", "/index.html"):
					self.send_response(200)
					self.send_header('Content-type', 'text/html')
					self.end_headers()
					if not self.login:
						f = open(os.path.join(os.path.dirname(__file__), "webadmin", "index.html"))
						self.wfile.write(f.read())
						f.close()
					else:
						#Show the webadmin Page
						f = open(os.path.join(os.path.dirname(__file__), "webadmin", "config.html"))
						code_page = f.read()
						code_page = self.pyretro_interpreter(code_page)
						self.wfile.write(code_page)
						f.close()
				elif parsed_path.path in ("/config.htm", "/config.html"):
					#Show the webadmin Page
					if not self.login:
						self.send_response(200)
						self.send_header('Content-type', 'text/html')
						self.end_headers()
						f = open(os.path.join(os.path.dirname(__file__), "webadmin", "index.html"))
						self.wfile.write(f.read())
						f.close()
					else:
						if parsed_path[4]:
							#Actions
							parameters = string.split(parsed_path[4], "&")
							for parameter in parameters:
								param = string.split(parameter, "=")
								
								if param[0] == 'action':
									if param[1] == 'logout':
										cookie = Cookie.SimpleCookie()
										cookie["fake_session"] = ""
										
										self.send_response(301)
										self.send_header('Location', 'index.html')
										self.send_header('Content-type', 'text/html')
										self.send_header('Set-Cookie', cookie.output(header=''))
										self.end_headers()
										
										self.login = False
									elif param[1] == 'shutdown_machine':
										self.message = "The machine shutdown in some seconds..."
										os.system(self.server.util.options['shutdown_command'])
										
										self.send_response(200)
										self.send_header('Content-type', 'text/html')
										self.end_headers()
									elif param[1] == 'reset_pyretro':
										self.send_response(200)
										self.send_header('Content-type', 'text/html')
										self.end_headers()
										
										self.message = "The PyRetro reset in some seconds..."
										
										f = open(os.path.join(os.path.dirname(__file__), "webadmin", "config.html"))
										code_page = f.read()
										code_page = self.pyretro_interpreter(code_page)
										self.wfile.write(code_page)
										f.close()
										
										self.server.exit = True
										self.thread_exit = threading.Thread(target=self.exit_thread)
										self.thread_exit.start()
									elif param[1] == 'exit_current_game':
										self.message = "The current game exit in some seconds..."
										
										self.send_response(200)
										self.send_header('Content-type', 'text/html')
										self.end_headers()
										
										self.kill_mame()
						
						if self.login:
							#Show the webadmin Page
							f = open(os.path.join(os.path.dirname(__file__), "webadmin", "config.html"))
							code_page = f.read()
							code_page = self.pyretro_interpreter(code_page)
							self.wfile.write(code_page)
							f.close()
						else:
							f = open(os.path.join(os.path.dirname(__file__), "webadmin", "index.html"))
							self.wfile.write(f.read())
							f.close()
							
				else:
					if parsed_path.path[0] == "/":
						resource = parsed_path.path[1:]
					else:
						resource = parsed_path.path
					
					#Avoid Cracks to access other files under the webadmin directory
					resource = re.sub(r'^(([.][.]([\]|[/]))*)(.*)$', r'\4', resource) 
					
					self.send_response(200)
					self.send_header('Content-type', 'application/octet-stream')
					self.end_headers()
					path_resource = os.path.join(os.path.dirname(__file__), "webadmin", resource)
					
					f = open(path_resource)
					self.wfile.write(f.read())
					f.close()
				
				return
			
			except IOError, message:
				print("Exception")
				pprint.pprint(message)
				self.send_error(404,'File Not Found: %s' % self.path)
		 
		
		def do_POST(self):
			try:
				if "Cookie" in self.headers:
					cookie = Cookie.SimpleCookie(self.headers["Cookie"])
					fake_session = cookie['fake_session'].value
					
					check_fake_session = md5.new()
					check_fake_session.update("salt_pyretro" + self.server.util.options['webadmin_password'])
					check_fake_session = check_fake_session.hexdigest()
					
					if check_fake_session == fake_session:
						self.login = True
					else:
						self.login = False
				
				ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
				if ctype == 'multipart/form-data':
					postvars = cgi.parse_multipart(self.rfile, pdict)
				elif ctype == 'application/x-www-form-urlencoded':
					length = int(self.headers.getheader('content-length'))
					postvars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1)
				else:
					postvars = {}
				
				
				if not self.login:
					if 'password' in postvars:
						if postvars['password'][0] != self.server.util.options['webadmin_password']:
							self.send_response(200)
							self.send_header('Content-type', 'text/html')
							self.end_headers()
							
							f = open(os.path.join(os.path.dirname(__file__), "webadmin", "index_login_fail.html"))
							self.wfile.write(f.read())
							f.close()
						else:
							self.login = True
							
							#MD5 Salted
							cookie = Cookie.SimpleCookie()
							fake_session = md5.new()
							fake_session.update("salt_pyretro" + postvars['password'][0])
							cookie["fake_session"] = fake_session.hexdigest()
							
							self.send_response(200)
							self.send_header('Content-type', 'text/html')
							self.send_header('Set-Cookie', cookie.output(header=''))
							self.end_headers()
							
							f = open(os.path.join(os.path.dirname(__file__),"webadmin", "config.html"))
							code_page = f.read()
							code_page = self.pyretro_interpreter(code_page)
							self.wfile.write(code_page)
							f.close()
				else:
					#Set by default the checkboxes as 0 because the checkboxs unset is not in the postvar
					self.server.util.options["debug"] = 0
					self.server.util.options["windowed"] = 0
					self.server.util.options["shutdown_on_exit"] = 0
					self.server.util.options["can_played_game_show_in_screensaver"] = 0
					self.server.util.options["filter"] = 0
					self.server.util.options["user_can_edit_favorities"] = 0
					self.server.util.options["webadmin"] = 0
					
					for name_post_var in postvars:
						if name_post_var in self.server.util.options:
							#Check is integer
							if name_post_var in ("view_mode", "screen_width", "screen_height", "time_to_show_screensaver", "seconds_wait_between_screensaver_images", "can_played_game_show_in_screensaver", "seconds_wait_video", "random_percent_default_images_screensaver", "transational_effect_screensaver", "shutdown_on_exit", "filter", "filter_game_buttons", "user_can_edit_favorities", "webadmin", "webadmin_port", "windowed", "debug"):
								self.server.util.options[name_post_var] = int(postvars[name_post_var][0])
							else:
								self.server.util.options[name_post_var] = postvars[name_post_var][0]
					
					self.server.util.save_config_file()
					
					self.send_response(200)
					self.send_header('Content-type', 'text/html')
					self.end_headers()
					
					self.message = "The PyRetro is updated, please wait to reboot the app."
					
					f = open(os.path.join(os.path.dirname(__file__), "webadmin", "config.html"))
					code_page = f.read()
					code_page = self.pyretro_interpreter(code_page)
					self.wfile.write(code_page)
					f.close()
					
					self.server.exit = True
					self.thread_exit = threading.Thread(target=self.exit_thread)
					self.thread_exit.start()
			
			except IOError, message:
				print("Exception")
				pprint.pprint(message)
				self.send_error(404,'File Not Found: %s' % self.path)
		
		
		def log_message(self, *args, **vargs):
			#Mute the log
			pass
		
		def pyretro_interpreter(self, pyretro_code):
			regex = re.compile("[<][?]pyretro(.+)[?][>]")
			for match in regex.finditer(pyretro_code):
				token = match.group(1)
				if re.search("(.*)[{](.*)[}](.*)", token):
					#Pseudocode
					pseudocode_str = re.sub(r'(.*)[{](.+)[}](.*)', r'\2', token)
					pseudocode = string.split(pseudocode_str, ";")
					
					operation = string.split(pseudocode[0], " ")
					
					#At the moment, it is only the if.
					if operation[0] == "if":
						if operation[1] == "message":
							#Show message
							
							message_html = ""
							if self.message:
								message_html = re.sub("[%]message[%]", self.message, pseudocode[1])
							
							pyretro_code = re.sub("[<][?]pyretro" + token + "[?][>]", \
								message_html, pyretro_code)
							
						else:
							item1 = re.findall(r'(.+)[ ](.+)((==)|(>)|(<)|(>=)|(<=)|(<>))', pseudocode[0])
							item1 = item1[0][1].strip()
							
							op = re.findall(r'((==)|(>)|(<)|(>=)|(<=)|(<>))', pseudocode[0])
							op = op[0][0]
							
							item2 = re.findall(r'((==)|(>)|(<)|(>=)|(<=)|(<>))(.+)', pseudocode[0])
							item2 = item2[0][7].strip()
							
							doThen = False
							doElse = True
							if op == "==":
								if type(self.server.util.options[item1]) is bool:
									val = int(self.server.util.options[item1])
								else:
									val = self.server.util.options[item1]
								if str(val) == str(item2):
									doThen = True
									doFalse = False
							elif op == "<>":
								if str(self.server.util.options[item1]) != str(item2):
									doThen = True
									doFalse = False
							elif op == ">=":
								if int(self.server.util.options[item1]) >= int(item2):
									doThen = True
									doFalse = False
							elif op == "<=":
								if int(self.server.util.options[item1]) <= int(item2):
									doThen = True
									doFalse = False
							elif op == "<":
								if int(self.server.util.options[item1]) < int(item2):
									doThen = True
									doFalse = False
							elif op == ">":
								if int(self.server.util.options[item1]) > int(item2):
									doThen = True
									doFalse = False
							
							
							if doThen:
								pyretro_code = re.sub("[<][?]pyretro" + token + "[?][>]", \
									pseudocode[1], pyretro_code)
							elif (doElse) and (len(operation) > 3):
								pyretro_code = re.sub("[<][?]pyretro" + token + "[?][>]", \
									pseudocode[2], pyretro_code)
							else:
								pyretro_code = re.sub("[<][?]pyretro" + token + "[?][>]", \
									"", pyretro_code)
				
				
				else:
					token = re.sub(r'(.*)[%](.+)[%](.*)', r'\2', token)
					
					if token in self.server.util.options:
						#Replace
						pyretro_code = re.sub("[<][?]pyretro(.+)[%]" + token + "[%](.+)[?][>]", \
							str(self.server.util.options[token]), pyretro_code)
					else:
						#Only clean
						pyretro_code = re.sub("<?pyretro(.+)[%]" + token + "[%][?][>]", \
							"", pyretro_code)
			
			return pyretro_code
	
	
	def run_thread(self):
		self.server = self.MyHTTPServer(('', self.util.options['webadmin_port']), self.Server)
		self.server.util = self.util
		print('Started webadmin...')
		self.server.serve_forever()
		
	
	
	def stop(self):
		self.stop = True
		if self.server:
			self.server.socket.close()
			self.server.shutdown()
		print('Stoped webadmin...')
		while self.thread.isAlive():
			time.sleep(1)
			sys.stdout.write(".")
			sys.stdout.flush()
		sys.stdout.write("\n")
		if self.thread:
			self.thread.join()
	
	
	def run(self):
		self.thread = threading.Thread(target=self.run_thread)
		self.thread.start()